package noema.session;

import javax.annotation.PostConstruct;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;

import noema.dataModel.Patient;
import noema.interceptor.LoggerInterceptor;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.persistence.jpa.JPAKnowledgeService;
import org.drools.runtime.Environment;
import org.drools.runtime.EnvironmentName;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.process.WorkItemHandler;
import org.jbpm.process.audit.JPAWorkingMemoryDbLogger;

@Interceptors({ LoggerInterceptor.class })
@Stateless
public class SessionFactoryImpl implements SessionFactory {

	@PersistenceUnit(unitName = "org.jbpm.persistence.jpa")
	private EntityManagerFactory engineEmf;
	@PersistenceUnit(unitName = "application.data")
	private EntityManagerFactory applicationEmf;
	@EJB(beanName = "MyHumanTaskClient")
	private WorkItemHandler humanTaskHandler;
	@EJB(beanName = "MyHumanTaskClient")
	private WorkItemHandler serviceTaskHandler;
	private KnowledgeBase kbase;
	private Environment env;

	@PostConstruct
	public void init() {
		if (applicationEmf == null || engineEmf == null) {
			throw new IllegalArgumentException(
					"Dependency injection didn't work");
		} else {
			KnowledgeBuilder kbuilder = KnowledgeBuilderFactory
					.newKnowledgeBuilder();
			kbuilder.add(ResourceFactory
					.newClassPathResource("persistenceSample.bpmn2"),
					ResourceType.BPMN2);
			kbuilder.add(ResourceFactory
					.newClassPathResource("dummyHospitalization.bpmn2"),
					ResourceType.BPMN2);
			kbuilder.add(ResourceFactory
					.newClassPathResource("setAnalysisRules.drl"),
					ResourceType.DRL);
			kbase = kbuilder.newKnowledgeBase();
			env = KnowledgeBaseFactory.newEnvironment();
			env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, engineEmf);
		}
	}

	@Override
	public StatefulKnowledgeSession getSession(Patient p) {
		EntityManager em = applicationEmf.createEntityManager();
		try {
			p = em.find(Patient.class, p.getHealthCardId());
			if (p == null) {
				throw new IllegalArgumentException("There isn't patient: " + p);
			}
			StatefulKnowledgeSession ksession = JPAKnowledgeService
					.loadStatefulKnowledgeSession(p.getSessionId(), kbase,
							null, env);
			new JPAWorkingMemoryDbLogger(ksession);
			ksession.getWorkItemManager().registerWorkItemHandler("Human Task",
					humanTaskHandler);
			ksession.getWorkItemManager().registerWorkItemHandler(
					"Service Task", serviceTaskHandler);
			// TODO registrare altri componenti alla sessione
		} finally {
			em.close();
		}
		return null;
	}

	@Override
	public StatefulKnowledgeSession getSessionByHealthCardId(String cardId) {
		EntityManager em = applicationEmf.createEntityManager();
		try {
			Query q = em
					.createQuery("SELECT p FROM Patient p WHERE p.healthCardId = :cardId");
			q.setParameter("cardId", cardId);
			Patient p = (Patient) q.getSingleResult();
			StatefulKnowledgeSession ksession = null;
			if (p != null) {
				ksession = JPAKnowledgeService.loadStatefulKnowledgeSession(
						p.getSessionId(), kbase, null, env);
				new JPAWorkingMemoryDbLogger(ksession);
				ksession.getWorkItemManager().registerWorkItemHandler(
						"Human Task", humanTaskHandler);
				ksession.getWorkItemManager().registerWorkItemHandler(
						"Service Task", serviceTaskHandler);
				// TODO registrare altri componenti alla sessione
			} else {
				throw new IllegalArgumentException("No patient with id="
						+ cardId);
			}
		} finally {
			em.close();
		}
		return null;
	}

	@Override
	public StatefulKnowledgeSession getSessionByProcessInstanceId(long id) {
		EntityManager em = applicationEmf.createEntityManager();
		try {
			Query q = em
					.createQuery("SELECT p FROM Patient p WHERE :processIds MEMBER OF p.processIds");
			q.setParameter("processIds", id);
			Patient p = (Patient) q.getSingleResult();
			StatefulKnowledgeSession ksession = null;
			if (p != null) {
				ksession = JPAKnowledgeService.loadStatefulKnowledgeSession(
						p.getSessionId(), kbase, null, env);
				new JPAWorkingMemoryDbLogger(ksession);
				ksession.getWorkItemManager().registerWorkItemHandler(
						"Human Task", humanTaskHandler);
				ksession.getWorkItemManager().registerWorkItemHandler(
						"Service Task", serviceTaskHandler);
				// TODO registrare altri componenti alla sessione
			} else {
				throw new IllegalArgumentException(
						"No patient with process instance with id=" + id);
			}
		} finally {
			em.close();
		}
		return null;
	}

	@Override
	public StatefulKnowledgeSession getNewSession() {
		StatefulKnowledgeSession ksession = null;
		ksession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null,
				env);
		new JPAWorkingMemoryDbLogger(ksession);
		ksession.getWorkItemManager().registerWorkItemHandler("Human Task",
				humanTaskHandler);
		ksession.getWorkItemManager().registerWorkItemHandler("Service Task",
				serviceTaskHandler);
		// TODO registrare altri componenti alla sessione
		return ksession;
	}
}
